AWS LambdaでS3 Selectをした際のパフォーマンス比較
こんにちは。サービスグループの武田です。
先日、頑張ってAWS LambdaのコンテナでRustアプリケーションからS3 Selectを実行してみました。
最後に 予想より実行時間が長い結果となりました と書いたのですが、じゃあどれくらいなら満足できるのか。というわけで、Lambdaで採用されることが多いであろうPythonとJavaScriptで同様の処理を書いて比較してみました。
Rust(+ AWS CLI) vs Python vs JavaScript
実行したソースコードはそれぞれ次のものです。なおRustは先述のエントリそのままですので省略します。
import boto3 import json s3 = boto3.client("s3") def lambda_handler(event, context): params = { "Bucket": "testdata-xxxx", "Key": "test_data.json", "InputSerialization": { "JSON": { "Type": "LINES", } }, "OutputSerialization": { "JSON": { "RecordDelimiter": "\n", } }, "ExpressionType": "SQL", "Expression": "SELECT * FROM s3object s", } res = s3.select_object_content(**params) text = "" for event in res["Payload"]: if "Records" in event: raw = event["Records"]["Payload"].decode("UTF-8") text += raw for line in text.splitlines(): print(json.loads(line))
const AWS = require('aws-sdk'); const S3 = new AWS.S3(); exports.handler = async (event) => { const params = { Bucket: 'testdata-xxxx', Key: 'test_data.json', InputSerialization: { JSON: { Type: 'LINES', } }, OutputSerialization: { JSON: { RecordDelimiter: '\n', } }, ExpressionType: 'SQL', Expression: 'SELECT * FROM s3object s', }; const res = await S3.selectObjectContent(params).promise(); let text = ''; const events = res.Payload; for await (const event of events) { if (event.Records) { text += event.Records.Payload.toString(); } } for (line of text.split('\n').filter(line => line !== '')) { console.log(JSON.parse(line)); } };
実行結果は次のようになりました。なおいずれも2回目〜6回目の結果を採用し、イニシャルコストは含まれていません。またJavaScriptについてはKeepAliveがデフォルトで無効化されているため、有効化しました。
Rust + AWS CLIの結果。
START RequestId: c66a065d-6673-469d-9db9-d1e251e1e4fe Version: $LATEST [2021-02-26T02:23:29Z DEBUG rust_lambda_call_aws_cli] handler start [2021-02-26T02:23:31Z DEBUG rust_lambda_call_aws_cli] Output { status: ExitStatus(ExitStatus(0)), stdout: "", stderr: "" } [2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Test", code: 1939, tags: Some("Dev"), lang: Some("ja") } [2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "IT Division", code: 1, tags: Some("Prod"), lang: Some("ja") } [2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Sample", code: 31, tags: None, lang: Some("en") } [2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Classmethod", code: 2, tags: None, lang: Some("en") } [2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Classmethod2", code: 19, tags: None, lang: None } END RequestId: c66a065d-6673-469d-9db9-d1e251e1e4fe
REPORT RequestId: 8e9f49c0-6b91-40e3-81f3-f7636abb8546 Duration: 2459.43 ms Billed Duration: 2460 ms Memory Size: 512 MB Max Memory Used: 46 MB REPORT RequestId: 848f0aa9-fca2-46e7-8942-d7a37bd2433d Duration: 2487.36 ms Billed Duration: 2488 ms Memory Size: 512 MB Max Memory Used: 47 MB REPORT RequestId: 2b5831ad-c1a3-4df3-b50b-db600eed5af9 Duration: 2463.11 ms Billed Duration: 2464 ms Memory Size: 512 MB Max Memory Used: 47 MB REPORT RequestId: 34fd1cdb-b7cb-4e55-8c9a-5b6c136e3b53 Duration: 2483.41 ms Billed Duration: 2484 ms Memory Size: 512 MB Max Memory Used: 47 MB REPORT RequestId: 99f64d9c-7acb-481d-b617-e3fc9314f595 Duration: 2501.80 ms Billed Duration: 2502 ms Memory Size: 512 MB Max Memory Used: 47 MB
Pythonの結果。
START RequestId: 16797d8f-6abf-47f2-ab02-7414e89bf5d2 Version: $LATEST {'name': 'Test', 'code': 1939, 'tags': 'Dev', 'lang': 'ja'} {'name': 'IT Division', 'code': 1, 'tags': 'Prod', 'lang': 'ja'} {'name': 'Sample', 'code': 31, 'lang': 'en'} {'name': 'Classmethod', 'code': 2, 'lang': 'en'} {'name': 'Classmethod2', 'code': 19} END RequestId: 16797d8f-6abf-47f2-ab02-7414e89bf5d2
REPORT RequestId: cb8cb604-6153-4f51-884f-4b782122119c Duration: 179.49 ms Billed Duration: 180 ms Memory Size: 128 MB Max Memory Used: 80 MB REPORT RequestId: 715763e4-f6dd-4bb0-8c0a-0173ccf63d2b Duration: 24.90 ms Billed Duration: 25 ms Memory Size: 128 MB Max Memory Used: 81 MB REPORT RequestId: 3baf17be-2a6b-4e6f-b522-4aee942c43cb Duration: 37.96 ms Billed Duration: 38 ms Memory Size: 128 MB Max Memory Used: 80 MB REPORT RequestId: 3c5aae3a-2575-4364-a7b9-927e6554d446 Duration: 42.81 ms Billed Duration: 43 ms Memory Size: 128 MB Max Memory Used: 80 MB REPORT RequestId: 51f995a3-20a7-4251-8713-bd8f64aea187 Duration: 40.54 ms Billed Duration: 41 ms Memory Size: 128 MB Max Memory Used: 80 MB
JavaScriptの結果。
START RequestId: e75761b2-4583-4cb1-8c11-d3f2287b65aa Version: $LATEST 2021-02-26T02:37:22.180Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Test', code: 1939, tags: 'Dev', lang: 'ja' } 2021-02-26T02:37:22.187Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'IT Division', code: 1, tags: 'Prod', lang: 'ja' } 2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Sample', code: 31, lang: 'en' } 2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Classmethod', code: 2, lang: 'en' } 2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Classmethod2', code: 19 } END RequestId: e75761b2-4583-4cb1-8c11-d3f2287b65aa
REPORT RequestId: 74d14063-63f4-4416-a991-4baf4eec444d Duration: 70.48 ms Billed Duration: 71 ms Memory Size: 128 MB Max Memory Used: 89 MB REPORT RequestId: e4cf838f-d085-403b-952f-5f7a10e9c89e Duration: 532.37 ms Billed Duration: 533 ms Memory Size: 128 MB Max Memory Used: 90 MB REPORT RequestId: 27896427-f6f8-4672-945a-371dfe271b73 Duration: 44.37 ms Billed Duration: 45 ms Memory Size: 128 MB Max Memory Used: 90 MB REPORT RequestId: 8abc9ab1-6917-4e7d-8ace-681e9276ab60 Duration: 33.97 ms Billed Duration: 34 ms Memory Size: 128 MB Max Memory Used: 90 MB REPORT RequestId: 4edaa2e8-8cbb-4bfe-b547-6837e87f731b Duration: 33.67 ms Billed Duration: 34 ms Memory Size: 128 MB Max Memory Used: 90 MB
PythonとJavaScriptは早いですね。計測回数が少ないので外れ値が目立ちますが、おそらく回数を増やせばいい具合に収束すると思われます。
一番問題なのは、Rust + AWS CLIはメモリ割り当てを512MBに上げてこの遅さなんですよね。外部コマンド呼び出しが悪いのか、一度ファイルに書き出しているのが遅さの原因なのか。そこまで調べきれていませんが、PythonやJavaScriptの最高速と比べて2桁違うのは結構な違いかと思われます。
まとめ
結構頑張ってRustからS3 Selectをやってみたものの、比較してみると採用はしにくそうです。これであれば、AWS CLI経由ではなくて、 S3 Selectを実行するPython Lambda関数 をRustから呼び出した方が早そうですね。